package com.mars.nacos.api.controller;

import com.google.common.collect.Lists;
import com.mars.nacos.domian.service.FlowableService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.engine.*;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.image.ProcessDiagramGenerator;
import org.flowable.task.api.Task;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;

/**
 * @author : kyrie
 * @date : 2022/9/7 09:49
 * #desc    : some description
 */
@Api(tags = "流程设计API")
@RestController
@Slf4j
@RequestMapping("/flow")
public class FlowableController {
    @Resource
    private RuntimeService runtimeService;
    @Resource
    private TaskService taskService;
    @Resource
    private RepositoryService repositoryService;
    @Resource
    private ProcessEngine processEngine;

    @Resource
    private FlowableService flowableService;

    /**
     * 通过接收用户的一个请求传入用户的ID和金额以及描述信息来开启一个报销流程，并返回给用户这个流程的Id添加报销
     * @param userId 用户id
     * @param money  报销金额
     * @param desc   报销备注
     */
    @ApiOperation(value = "添加报销", notes = "添加报销")
    @GetMapping("/v1/add")
    public String addExpense(String userId, Integer money, String desc) {
        return flowableService.addExpense(userId, money, desc);
    }

    /**
     * 查询流程列表，待办列表，通过代码获取出用户需要处理的流程
     * 获取审批管理列表
     */
    @ApiOperation(value = "获取审批管理列表", notes = "获取审批管理列表")
    @GetMapping("/v1/list")
    public Object list(String userId) {
        return flowableService.findList(userId);
    }

    /**
     * 批准，通过前端传入的任务ID来对此流程进行同意处理
     * @param taskId 任务ID
     */
    @ApiOperation(value = "审批通过", notes = "审批通过")
    @GetMapping("/v1/apply")
    public String apply(String taskId) {
        return flowableService.apply(taskId);
    }

    /**
     * 拒绝
     */
    @ApiOperation(value = "审批拒绝", notes = "审批拒绝")
    @GetMapping("/v1/reject")
    public String reject(String taskId) {
        return flowableService.reject(taskId);
    }

    /**
     * 生成当前流程图表
     * 生成流程图
     * @param processId 任务ID
     */
    @ApiOperation(value = "生成流程图", notes = "生成流程图")
    @GetMapping("/v1/processDiagram")
    public void genProcessDiagram(HttpServletResponse httpServletResponse, String processId) throws Exception {
        ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
        //流程走完的不显示图
        if (pi == null) {
            return;
        }
        Task task = taskService.createTaskQuery().processInstanceId(pi.getId()).singleResult();
        //使用流程实例ID，查询正在执行的执行对象表，返回流程实例对象
        String InstanceId = task.getProcessInstanceId();
        List<Execution> executions = runtimeService
                .createExecutionQuery()
                .processInstanceId(InstanceId)
                .list();

        //得到正在执行的Activity的Id
        List<String> activityIds = Lists.newArrayList();
        List<String> flows = Lists.newArrayList();
        for (Execution exe : executions) {
            List<String> ids = runtimeService.getActiveActivityIds(exe.getId());
            activityIds.addAll(ids);
        }

        //图片输出要加上这个不会显示二进制数据，有些浏览器正常，有些浏览器是直接显示二进制数据,因此修改
        httpServletResponse.setContentType("image/png".concat(";charset=UTF-8"));

        //获取流程图
        BpmnModel bpmnModel = repositoryService.getBpmnModel(pi.getProcessDefinitionId());
        ProcessEngineConfiguration engconf = processEngine.getProcessEngineConfiguration();
        ProcessDiagramGenerator diagramGenerator = engconf.getProcessDiagramGenerator();
        InputStream in = diagramGenerator.generateDiagram(bpmnModel, "png", activityIds, flows, engconf.getActivityFontName(), engconf.getLabelFontName(), engconf.getAnnotationFontName(), engconf.getClassLoader(), 1.0,true);
        OutputStream out = null;
        byte[] buf = new byte[1024];
        int legth = 0;
        try {
            out = httpServletResponse.getOutputStream();
            while ((legth = in.read(buf)) != -1) {
                out.write(buf, 0, legth);
            }
        } finally {
            if (in != null) {
                in.close();
            }
            if (out != null) {
                out.close();
            }
        }
    }
}
